#pragma once

#include <efi/efi.hpp>
#include <efi/memory.hpp>

#include <optional>

#define EFI_LOAD_FILE_PROTOCOL_GUID                                            \
  {                                                                            \
    0x56ec3091, 0x954c, 0x11d2, {                                              \
      0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b                           \
    }                                                                          \
  }

#define EFI_LOAD_FILE2_PROTOCOL_GUID                                           \
  {                                                                            \
    0x4006c0c1, 0xfcb3, 0x403e, {                                              \
      0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d                           \
    }                                                                          \
  }

#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID                                   \
  {                                                                            \
    0x0964e5b22, 0x6459, 0x11d2, {                                             \
      0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b                           \
    }                                                                          \
  }

#define EFI_FILE_INFO_GUID                                                     \
  {                                                                            \
    0x09576e92, 0x6d3f, 0x11d2, {                                              \
      0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b                           \
    }                                                                          \
  }

#define EFI_FILE_SYSTEM_INFO_GUID                                              \
  {                                                                            \
    0x09576e93, 0x6d3f, 0x11d2, {                                              \
      0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b                           \
    }                                                                          \
  }

#define EFI_FILE_SYSTEM_VOLUME_LABEL_GUID                                      \
  {                                                                            \
    0xdb47d7d3, 0xfe81, 0x11d3, {                                              \
      0x9a, 0x35, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d                           \
    }                                                                          \
  }

#define EFI_TAPE_IO_PROTOCOL_GUID                                              \
  {                                                                            \
    0x1e93e633, 0xd65a, 0x459e, {                                              \
      0xab, 0x84, 0x93, 0xd9, 0xec, 0x26, 0x6d, 0x18                           \
    }                                                                          \
  }

#define EFI_DISK_IO_PROTOCOL_GUID                                              \
  {                                                                            \
    0xce345171, 0xba0b, 0x11d2, {                                              \
      0x8e, 0x4f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b                           \
    }                                                                          \
  }

#define EFI_DISK_IO2_PROTOCOL_GUID                                             \
  {                                                                            \
    0x151c8eae, 0x7f2c, 0x472c, {                                              \
      0x9e, 0x54, 0x98, 0x28, 0x19, 0x4f, 0x6a, 0x88                           \
    }                                                                          \
  }

#define EFI_BLOCK_IO_PROTOCOL_GUID                                             \
  {                                                                            \
    0x964e5b21, 0x6459, 0x11d2, {                                              \
      0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b                           \
    }                                                                          \
  }

#define EFI_BLOCK_IO2_PROTOCOL_GUID                                            \
  {                                                                            \
    0xa77b2472, 0xe282, 0x4e9f, {                                              \
      0xa2, 0x45, 0xc2, 0xc0, 0xe2, 0x7b, 0xbc, 0xc1                           \
    }                                                                          \
  }

#define EFI_BLOCK_IO_CRYPTO_PROTOCOL_GUID                                      \
  {                                                                            \
    0xa00490ba, 0x3f1a, 0x4b4c, {                                              \
      0xab, 0x90, 0x4f, 0xa9, 0x97, 0x26, 0xa1, 0xe8                           \
    }                                                                          \
  }

#define EFI_ERASE_BLOCK_PROTOCOL_GUID                                          \
  {                                                                            \
    0x95a9a93e, 0xa86e, 0x4926, {                                              \
      0xaa, 0xef, 0x99, 0x18, 0xe7, 0x72, 0xd9, 0x87                           \
    }                                                                          \
  }

#define EFI_ATA_PASS_THRU_PROTOCOL_GUID                                        \
  {                                                                            \
    0x1d3de7f0, 0x807, 0x424f, {                                               \
      0xaa, 0x69, 0x11, 0xa5, 0x4e, 0x19, 0xa4, 0x6f                           \
    }                                                                          \
  }

#define EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID                             \
  {                                                                            \
    0xc88b0b6d, 0x0dfc, 0x49a7, {                                              \
      0x9c, 0xb4, 0x49, 0x7, 0x4b, 0x4c, 0x3a, 0x78                            \
    }                                                                          \
  }

#define EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL_GUID                                \
  {                                                                            \
    0x52c78312, 0x8edc, 0x4233, {                                              \
      0x98, 0xf2, 0x1a, 0x1a, 0xa5, 0xe3, 0x88, 0xa5                           \
    }                                                                          \
  }

#define EFI_SD_MMC_PASS_THRU_PROTOCOL_GUID                                     \
  {                                                                            \
    0x716ef0d9, 0xff83, 0x4f69, {                                              \
      0x81, 0xe9, 0x51, 0x8b, 0xd3, 0x9a, 0x8e, 0x70                           \
    }                                                                          \
  }

#define EFI_RAM_DISK_PROTOCOL_GUID                                             \
  {                                                                            \
    0xab38a0df, 0x6873, 0x44a9, {                                              \
      0x87, 0xe6, 0xd4, 0xeb, 0x56, 0x14, 0x84, 0x49                           \
    }                                                                          \
  }

#define EFI_PARTITION_INFO_PROTOCOL_GUID                                       \
  {                                                                            \
    0x8cf2f62c, 0xbc9b, 0x4821, {                                              \
      0x80, 0x8d, 0xec, 0x9e, 0xc4, 0x21, 0xa1, 0xa0                           \
    }                                                                          \
  }

#define EFI_NVDIMM_LABEL_PROTOCOL_GUID                                         \
  {                                                                            \
    0xd40b6b80, 0x97d5, 0x4282, {                                              \
      0xbb, 0x1d, 0x22, 0x3a, 0x16, 0x91, 0x80, 0x58                           \
    }                                                                          \
  }

#define EFI_UFS_DEVICE_CONFIG_GUID                                             \
  {                                                                            \
    0xb81bfab0, 0xeb3, 0x4cf9, {                                               \
      0x84, 0x65, 0x7f, 0xa9, 0x86, 0x36, 0x16, 0x64                           \
    }                                                                          \
  }

#define EFI_FILE_MODE_READ BIT(0)
#define EFI_FILE_MODE_WRITE BIT(1)
#define EFI_FILE_MODE_CREATE BIT(63)

#define EFI_FILE_READ_ONLY BIT(0)
#define EFI_FILE_HIDDEN BIT(1)
#define EFI_FILE_SYSTEM BIT(2)
#define EFI_FILE_RESERVED BIT(3)
#define EFI_FILE_DIRECTORY BIT(4)
#define EFI_FILE_ARCHIVE BIT(5)
#define EFI_FILE_VALID_ATTR                                                    \
  (EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM | EFI_FILE_RESERVED  \
   | EFI_FILE_DIRECTORY | EFI_FILE_ARCHIVE)

// 用于BlockIoCryptoProtocol

#define EFI_BLOCK_IO_CRYPTO_INDEX_ANY (~0ull)

// 用于AtaPassThruProtocol::Mode::attributes

#define EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL BIT(0)
#define EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL BIT(1)
#define EFI_ATA_PASS_THRU_ATTRIBUTES_NONBLOCKIO BIT(2)

// 用于AtaPassThruProtocol::CommandPacket::lengthType

#define EFI_ATA_PASS_THRU_LENGTH_BYTES 0x80
#define EFI_ATA_PASS_THRU_LENGTH_MASK 0x70
#define EFI_ATA_PASS_THRU_LENGTH_NO_DATA_TRANSFER 0x00
#define EFI_ATA_PASS_THRU_LENGTH_FEATURES 0x10
#define EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT 0x20
#define EFI_ATA_PASS_THRU_LENGTH_TPSIU 0x30
#define EFI_ATA_PASS_THRU_LENGTH_COUNT 0x0F

// 用于NvmExpressPassThruProtocol::Mode::attributes

#define EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL BIT(0)
#define EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL BIT(1)
#define EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_NONBLOCKIO BIT(2)
#define EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM BIT(3)

// 用于NvmExpressPassThruProtocol::NvmeCdw0::fusedOperation

#define NORMAL_CMD 0x00
#define FUSED_FIRST_CMD 0x01
#define FUSED_SECOND_CMD 0x02

namespace efi {

typedef uint64_t LBA;

typedef struct {
  typedef struct {
    uint8_t bootIndicator;
    uint8_t startHead;
    uint8_t startSector;
    uint8_t startTrack;
    uint8_t osIndicator;
    uint8_t endHead;
    uint8_t endSector;
    uint8_t endTrack;
    uint8_t startingLBA[4];
    uint8_t sizeInLBA[4];
  } __attribute__((packed)) PartitionRecord;

  uint8_t bootStrapCode[440];
  uint8_t uniqueMbrSignature[4];
  uint8_t unknown[2];
  PartitionRecord partition[4];
  uint16_t signature;
} __attribute__((packed)) MasterBootRecord;

typedef struct {
  Guid partitionTypeGUID;
  Guid uniquePartitionGUID;
  LBA startingLBA;
  LBA endingLBA;
  uint64_t attributes;
  char16_t partitionName[36];
} __attribute__((packed)) GptPartitionEntry;

typedef struct LoadFileProtocol {
  typedef Status(EFIAPI *LoadFile)(
      IN struct LoadFileProtocol *instance,
      IN DevicePath *filePath,
      IN bool bootPolicy,
      IN OUT uint64_t *size,
      IN void *buffer OPTIONAL
  );

  LoadFile loadFile;
} LoadFileProtocol;

typedef struct LoadFile2Protocol {
  typedef Status(EFIAPI *LoadFile)(
      IN struct LoadFileProtocol *instance,
      IN DevicePath *filePath,
      IN bool bootPolicy, // 应总是传入false
      IN OUT uint64_t *size,
      IN void *buffer OPTIONAL
  );

  LoadFile loadFile;
} LoadFile2Protocol;

struct FileProtocol;

typedef struct SimpleFilesystemProtocol {
  typedef Status(EFIAPI *OpenVolume)(
      IN SimpleFilesystemProtocol *instance,
      OUT struct FileProtocol **root
  );

  uint64_t revision;
  OpenVolume openVolume;
} SimpleFilesystemProtocol;

typedef struct FileProtocol {
  typedef struct {
    Event::Instance event;
    Status status;
    uint64_t bufferSize;
    void *buffer;
  } IoToken;

  typedef struct {
    uint64_t size;
    uint64_t fileSize;
    uint64_t physicalSize;
    Time::Time createTime;
    Time::Time lastAccessTime;
    Time::Time modificationTime;
    uint64_t attribute;
    char16_t fileName[];
  } FileInfo;

  typedef struct {
    uint64_t size;
    bool readOnly;
    uint64_t volumeSize;
    uint64_t freeSpace;
    uint32_t blockSize;
    char16_t volumeLabel[];
  } FileSystemInfo;

  typedef struct {
    char16_t volumeLabel[0];
  } VolumeLabelInfo;

  typedef Status(EFIAPI *Open)(
      IN struct FileProtocol *instance,
      OUT struct FileProtocol **newHandle,
      IN const char16_t *fileName,
      IN uint64_t openMode,
      IN uint64_t attributes
  );

  typedef Status(EFIAPI *Close)(IN struct FileProtocol *instance);

  typedef Status(EFIAPI *Remove)(IN struct FileProtocol *instance);

  typedef Status(EFIAPI *Read)(
      IN struct FileProtocol *instance,
      IN OUT uint64_t *bufferSize,
      OUT void *buffer
  );

  typedef Status(EFIAPI *Write)(
      IN struct FileProtocol *instance,
      IN OUT uint64_t *SIZE,
      IN void *daTA
  );

  typedef Status(EFIAPI *SetPosition)(
      IN struct FileProtocol *instance,
      IN uint64_t position
  );

  typedef Status(EFIAPI *GetPosition)(
      IN struct FileProtocol *instance,
      OUT uint64_t *position
  );

  typedef Status(EFIAPI *GetInfo)(
      IN struct FileProtocol *instance,
      IN Guid *informationType,
      IN OUT uint64_t *bufferSize,
      OUT void *buffer
  );

  typedef Status(EFIAPI *SetInfo)(
      IN struct FileProtocol *instance,
      IN Guid *informationType,
      IN uint64_t bufferSize,
      IN void *buffer
  );

  typedef Status(EFIAPI *Flush)(IN struct FileProtocol *instance);

  typedef Status(EFIAPI *OpenEx)(
      IN struct FileProtocol *instance,
      OUT struct FileProtocol **newHandle,
      IN const char16_t *fileName,
      IN uint64_t openMode,
      IN uint64_t attributes,
      IN IoToken *token
  );

  typedef Status(EFIAPI *FileOpEx)(
      IN struct FileProtocol *instance,
      IN IoToken *token
  );

  uint64_t revision;
  Open open;
  Close close;
  Remove remove;
  Read read;
  Write write;
  GetPosition getPosition;
  SetPosition setPosition;
  GetInfo getInfo;
  SetInfo setInfo;
  Flush flush;

  // 以下成员在revision大于等于2(>=0x00020000)时有效

  OpenEx openEx;
  FileOpEx readEx;
  FileOpEx writeEx;
  FileOpEx flushEx;
} FileProtocol;

class File {
  FileProtocol *file;

  File(FileProtocol *fp);

public:
  Status read(void *buf, size_t &size, off64_t offset = 0);
  PoolObject<uint8_t> readAll(size_t &size);

  Status write(const void *data, size_t &size);

  PoolObject<FileProtocol::FileInfo> getInfo();

  Status flush();
  Status close();

  operator FileProtocol *() { return this->file; }

  static std::optional<File> open(
      SimpleFilesystemProtocol *rootfs,
      const char16_t *path,
      uint64_t openMode,
      uint64_t attributes = 0
  );
};

typedef struct TapeIoProtocol {
  typedef struct {
    uint64_t signature; // = 0x544f4f4220494645
    uint32_t revision;
    uint32_t bootDescSize;
    uint32_t bootDescCRC;
    Guid tapeGUID;
    Guid tapeType;
    Guid tapeUnique;
    uint32_t blLocation;
    uint32_t blBlockSize;
    uint32_t blFileSize;
    char osVersion[40];
    char appVersion[40];
    char creationDate[10];
    char creationTime[10];
    char systemName[256]; // UTF-8
    char tapeTitle[120];  // UTF-8
    char pad[468];        // pad to 1024
  } TapeHeader;

  typedef Status(EFIAPI *Read)(
      IN struct TapeIoProtocol *instance,
      IN OUT uint64_t *size,
      OUT void *buffer
  );

  typedef Status(EFIAPI *Write)(
      IN struct TapeIoProtocol *instance,
      IN uint64_t *size,
      IN void *data
  );

  typedef Status(EFIAPI *Rewind)(IN struct TapeIoProtocol *instance);

  typedef Status(EFIAPI *Space)(
      IN struct TapeIoProtocol *instance,
      IN int64_t direction,
      IN uint64_t type
  );

  typedef Status(EFIAPI *WriteFileMarks)(
      IN struct TapeIoProtocol *instance,
      IN uint64_t count
  );

  typedef Status(EFIAPI *Reset)(
      IN struct TapeIoProtocol *instance,
      IN bool extendedVerification
  );

  Read read;
  Write write;
  Rewind rewind;
  Space space;
  WriteFileMarks writeFileMarks;
  Reset reset;
} TapeIoProtocol;

typedef struct DiskIoProtocol {
  typedef Status(EFIAPI *ReadDisk)(
      IN struct DiskIoProtocol *instance,
      IN uint32_t mediaId,
      IN uint64_t offset,
      IN uint64_t bufferSize,
      OUT void *buffer
  );

  typedef Status(EFIAPI *WriteDisk)(
      IN struct DiskIoProtocol *instance,
      IN uint32_t mediaId,
      IN uint64_t offset,
      IN uint64_t size,
      IN void *data
  );

  uint64_t revision;
  ReadDisk readDisk;
  WriteDisk writeDisk;
} DiskIoProtocol;

typedef struct DiskIo2Protocol {
  typedef struct {
    Event::Instance event;
    Status status;
  } IoToken;

  typedef Status(EFIAPI *Cancel)(IN struct DiskIo2Protocol *instance);

  typedef Status(EFIAPI *ReadEx)(
      IN struct DiskIo2Protocol *instance,
      IN uint32_t mediaId,
      IN uint64_t offset,
      IN OUT IoToken *token,
      IN uint64_t bufferSize,
      OUT void *buffer
  );

  typedef Status(EFIAPI *WriteEx)(
      IN struct DiskIo2Protocol *instance,
      IN uint32_t mediaId,
      IN uint64_t offset,
      IN OUT IoToken *token,
      IN uint64_t size,
      IN void *data
  );

  typedef Status(EFIAPI *FlushEx)(
      IN struct DiskIo2Protocol *instance,
      IN OUT IoToken *token
  );

  uint64_t revision;
  Cancel cancel;
  ReadEx readDiskEx;
  WriteEx writeDiskEx;
  FlushEx flushDiskEx;
} DiskIo2Protocol;

typedef struct BlockIoProtocol {
  typedef struct {
    uint32_t mediaId;
    bool removableMedia;
    bool mediaPresent;
    bool logicalPartition;
    bool readOnly;
    bool writeCaching;
    uint32_t blockSize;
    uint32_t ioAlign;
    LBA lastBlockLba;

    // 以下成员在revision>=0x00020001时有效

    LBA lowestAlignedLba;
    uint32_t logicalBlocksPerPhysicalBlock;

    // 以下成员在revision>=0x0002001f时有效

    uint32_t optimalTransferLengthGranularity;
  } Media;

  typedef Status(EFIAPI *Reset)(
      IN struct BlockIoProtocol *instance,
      IN bool extendedVerification
  );

  typedef Status(EFIAPI *Read)(
      IN struct BlockIoProtocol *instance,
      IN uint32_t mediaId,
      IN LBA lba,
      IN uint64_t bufferSize,
      OUT void *buffer
  );

  typedef Status(EFIAPI *Write)(
      IN struct BlockIoProtocol *instance,
      IN uint32_t MediaId,
      IN LBA lba,
      IN uint64_t size,
      IN void *data
  );

  typedef Status(EFIAPI *Flush)(IN struct BlockIoProtocol *instance);

  uint64_t revision;
  Media *media;
  Reset reset;
  Read readBlocks;
  Write writeBlocks;
  Flush flushBlocks;
} BlockIoProtocol;

typedef struct BlockIo2Protocol {
  typedef struct {
    Event::Instance event;
    Status status;
  } IoToken;

  typedef Status(EFIAPI *ReadBlocksEx)(
      IN struct BlockIo2Protocol *instance,
      IN uint32_t mediaId,
      IN LBA lba,
      IN OUT IoToken *token,
      IN uint64_t bufferSize,
      OUT void *buffer
  );

  typedef Status(EFIAPI *WriteBlocksEx)(
      IN struct BlockIo2Protocol *instance,
      IN uint32_t mediaId,
      IN LBA lba,
      IN OUT IoToken *Token,
      IN uint64_t size,
      IN void *data
  );

  typedef Status(EFIAPI *FlushBlocksEx)(
      IN struct BlockIo2Protocol *instance,
      IN OUT IoToken *token
  );

  BlockIoProtocol::Media *media;
  BlockIoProtocol::Reset reset;
  ReadBlocksEx readBlocksEx;
  WriteBlocksEx writeBlocksEx;
  FlushBlocksEx flushBlocksEx;
} BlockIo2Protocol;

typedef struct BlockIoCryptoProtocol {
  typedef struct {
    Guid algorithm;
    uint64_t keySize;
    uint64_t cryptoBlockSizeBitMask;
  } CryptoCapability;

  typedef struct {
    bool supported;
    uint64_t keyCount;
    uint64_t capabilityCount;
    CryptoCapability capabilities[1];
  } CryptoCapabilities;

  typedef struct {
    uint64_t index;
    Guid keyOwnerGuid;
    CryptoCapability capability;
    void *cryptoKey;
  } CryptoConfigurationTableEntry;

  typedef struct {
    uint64_t index;
    Guid keyOwnerGuid;
    CryptoCapability capability;
  } CryptoResponseConfigurationEntry;

  typedef Status(EFIAPI *Reset)(
      IN struct BlockIoCryptoProtocol *instance,
      IN bool extendedVerification
  );

  typedef Status(EFIAPI *GetCapabilities)(
      IN struct BlockIoCryptoProtocol *instance,
      OUT CryptoCapabilities *capabilities
  );

  typedef Status(EFIAPI *SetConfiguration)(
      IN struct BlockIoCryptoProtocol *instance,
      IN uint64_t configurationCount,
      IN CryptoConfigurationTableEntry *configurationTable,
      OUT CryptoResponseConfigurationEntry *resultingTable OPTIONAL
  );

  typedef Status(EFIAPI *GetConfiguration)(
      IN struct BlockIoCryptoProtocol *instance,
      IN uint64_t startIndex,
      IN uint64_t configurationCount,
      IN Guid *keyOwnerGuid OPTIONAL,
      OUT CryptoResponseConfigurationEntry *configurationTable
  );

  typedef Status(EFIAPI *ReadBlocksEx)(
      IN struct BlockIoCryptoProtocol *instance,
      IN uint32_t mediaId,
      IN LBA lba,
      IN OUT BlockIo2Protocol::IoToken *token,
      IN size_t bufferSize,
      OUT void *buffer,
      IN uint64_t *index OPTIONAL,
      IN void *cryptoIvInput OPTIONAL
  );

  typedef Status(EFIAPI *WriteBlocksEx)(
      IN struct BlockIoCryptoProtocol *instance,
      IN uint32_t mediaId,
      IN LBA lba,
      IN OUT BlockIo2Protocol::IoToken *token,
      IN uint64_t size,
      IN void *data,
      IN uint64_t *index,
      IN void *cryptoIvInput OPTIONAL
  );

  typedef Status(EFIAPI *FlushBlocks)(
      IN struct BlockIoCryptoProtocol *instance,
      IN OUT BlockIo2Protocol::IoToken *token
  );

  BlockIoProtocol::Media *media;
  Reset reset;
  GetCapabilities getCapabilities;
  SetConfiguration setConfiguration;
  GetConfiguration getConfiguration;
  ReadBlocksEx readBlocksEx;
  WriteBlocksEx writeBlocksEx;
  FlushBlocks flushBlocks;
} BlockIoCryptoProtocol;

typedef struct EraseBlockProtocol {
  typedef Status(EFIAPI *EraseBlocks)(
      IN BlockIoProtocol *instance,
      IN uint32_t mediaId,
      IN LBA lba,
      IN OUT BlockIo2Protocol::IoToken *Token,
      IN size_t size
  );

  uint64_t revision;
  uint32_t eraseLengthGranularity;
  EraseBlocks eraseBlocks;
} EraseBlockProtocol;

typedef struct AtaPassThruProtocol {
  typedef struct {
    uint32_t attributes;
    uint32_t ioAlign;
  } Mode;

  typedef struct {
    uint8_t reserved1[2];
    uint8_t ataCommand;
    uint8_t ataFeatures;
    uint8_t ataSectorNumber;
    uint8_t ataCylinderLow;
    uint8_t ataCylinderHigh;
    uint8_t ataDeviceHead;
    uint8_t ataSectorNumberExp;
    uint8_t ataCylinderLowExp;
    uint8_t ataCylinderHighExp;
    uint8_t ataFeaturesExp;
    uint8_t ataSectorCount;
    uint8_t ataSectorCountExp;
    uint8_t reserved2[6];
  } CommandBlock;

  typedef struct {
    uint8_t reserved1[2];
    uint8_t ataStatus;
    uint8_t ataError;
    uint8_t ataSectorNumber;
    uint8_t ataCylinderLow;
    uint8_t ataCylinderHigh;
    uint8_t ataDeviceHead;
    uint8_t ataSectorNumberExp;
    uint8_t ataCylinderLowExp;
    uint8_t ataCylinderHighExp;
    uint8_t reserved2;
    uint8_t ataSectorCount;
    uint8_t ataSectorCountExp;
    uint8_t reserved3[6];
  } StatusBlock;

  enum class CommandProtocol : uint8_t {
    AtaHardwareReset,
    AtaSoftwareReset,
    AtaNonData,
    PioDataIn = 4,
    PioDataOut,
    Dma,
    QueuedDma,
    DeviceDiagnostic,
    DeviceReset,
    UdmaDataIn,
    UdmaDataOut,
    Fpdma,
    ReturnResponse = 0xff
  };

  typedef struct {
    StatusBlock *status;
    CommandBlock *command;
    uint64_t timeout;
    void *inDataBuffer;
    void *outDataBuffer;
    uint32_t inTransferLength;
    uint32_t outTransferLength;
    CommandProtocol protocol;
    uint8_t lengthType;
  } CommandPacket;

  typedef Status(EFIAPI *PassThrough)(
      IN struct AtaPassThruProtocol *instance,
      IN uint16_t port,
      IN uint16_t portMultiplierPort,
      IN OUT CommandPacket *packet,
      IN Event::Instance event OPTIONAL
  );

  typedef Status(EFIAPI *GetNextPort)(
      IN struct AtaPassThruProtocol *instance,
      IN OUT uint16_t *port
  );

  typedef Status(EFIAPI *GetNextDevice)(
      IN struct AtaPassThruProtocol *instance,
      IN uint16_t port,
      IN OUT uint16_t *portMultiplierPort
  );

  typedef Status(EFIAPI *BuildDevicePath)(
      IN struct AtaPassThruProtocol *instance,
      IN uint16_t port,
      IN uint16_t portMultiplierPort,
      OUT DevicePath **devicePath
  );

  typedef Status(EFIAPI *GetDevice)(
      IN struct AtaPassThruProtocol *instance,
      IN DevicePath *devicePath,
      OUT uint16_t *port,
      OUT uint16_t *portMultiplierPort
  );

  typedef Status(EFIAPI *ResetPort)(
      IN struct AtaPassThruProtocol *instance,
      IN uint16_t port
  );

  typedef Status(EFIAPI *ResetDevice)(
      IN struct AtaPassThruProtocol *instance,
      IN uint16_t port,
      IN uint16_t portMultiplierPort
  );

  Mode *mode;
  PassThrough passThrough;
  GetNextPort getNextPort;
  GetNextDevice getNextDevice;
  BuildDevicePath buildDevicePath;
  GetDevice getDevice;
  ResetPort resetPort;
  ResetDevice resetDevice;
} AtaPassThruProtocol;

typedef struct StorageSecurityCommandProtocol {
  typedef Status(EFIAPI *ReceiveData)(
      IN struct StorageSecurityCommandProtocol *instance,
      IN uint32_t MediaId,
      IN uint64_t Timeout,
      IN uint8_t SecurityProtocol,
      IN uint16_t SecurityProtocolSpecificData,
      IN uint64_t PayloadBufferSize,
      OUT void *PayloadBuffer,
      OUT uint64_t *PayloadTransferSize
  );

  typedef Status(EFIAPI *SendData)(
      IN struct StorageSecurityCommandProtocol *instance,
      IN uint32_t MediaId,
      IN uint64_t Timeout,
      IN uint8_t SecurityProtocolId,
      IN uint16_t SecurityProtocolSpecificData,
      IN uint64_t PayloadBufferSize,
      IN void *PayloadBuffer
  );

  ReceiveData receiveData;
  SendData sendData;
} StorageSecurityCommandProtocol;

typedef struct NvmExpressPassThruProtocol {
  typedef struct {
    uint32_t attributes;
    uint32_t ioAlign;
    uint32_t nvmeVersion;
  } Mode;

  typedef struct {
    uint32_t opCode : 8;
    uint32_t fusedOperation : 2;
    uint32_t reserved : 22;
  } NvmeCdw0;

  typedef struct {
    NvmeCdw0 cdw0;
    uint8_t flags;
    uint32_t nsid;
    uint32_t cdw2;
    uint32_t cdw3;
    uint32_t cdw10;
    uint32_t cdw11;
    uint32_t cdw12;
    uint32_t cdw13;
    uint32_t cdw14;
    uint32_t cdw15;
  } Command;

  typedef struct {
    uint32_t data[4];
  } CompletionQueueEntry;

  typedef struct {
    uint64_t commandTimeout;
    void *transferBuffer OPTIONAL;
    uint32_t transferLength OPTIONAL;
    void *metaDataBuffer OPTIONAL;
    uint32_t metadataLength OPTIONAL;
    uint8_t queueType;
    Command *command;
    CompletionQueueEntry *completionQueueEntry;
  } CommandPacket;

  typedef Status(EFIAPI *PassThrough)(
      IN struct NvmExpressPassThruProtocol *instances,
      IN uint32_t namespaceId,
      IN OUT CommandPacket *packet,
      IN Event::Instance event OPTIONAL
  );

  typedef Status(EFIAPI *GetNextNamespace)(
      IN struct NvmExpressPassThruProtocol *instances,
      IN OUT uint32_t *namespaceId
  );

  typedef Status(EFIAPI *BuildDevicePath)(
      IN struct NvmExpressPassThruProtocol *instances,
      IN uint32_t namespaceId,
      OUT DevicePath **devicePath
  );

  typedef Status(EFIAPI *GetNamespace)(
      IN struct NvmExpressPassThruProtocol *instances,
      IN DevicePath *devicePath,
      OUT uint32_t *namespaceId
  );

  Mode *mode;
  PassThrough passThrough;
  GetNextNamespace getNextNamespace;
  BuildDevicePath buildDevicePath;
  GetNamespace getNamespace;
} NvmExpressPassThruProtocol;

typedef struct SdMmcPassThruProtocol {
  enum class CommandType : uint32_t {
    Bc,  // Broadcast commands, no response
    Bcr, // Broadcast commands with response
    Ac,  // Addressed(point-to-point) commands
    Adtc // Addressed(point-to-point) data transfer commands
  };

  enum class ResponseType : uint32_t {
    R1,
    R1b,
    R2,
    R3,
    R4,
    R5,
    R5b,
    R6,
    R7
  };

  typedef struct {
    uint16_t commandIndex;
    uint32_t commandArgument;
    CommandType commandType;
    ResponseType responseType;
  } CommandBlock;

  typedef struct {
    uint32_t responses[4];
  } StatusBlock;

  typedef struct {
    CommandBlock *sdMmcCmdBlk;
    StatusBlock *sdMmcStatusBlk;
    uint64_t timeout;
    void *inDataBuffer;
    void *outDataBuffer;
    uint32_t inTransferLength;
    uint32_t outTransferLength;
    Status transactionStatus;
  } CommandPacket;

  typedef Status(EFIAPI *PassThrough)(
      IN struct SdMmcPassThruProtocol *instance,
      IN uint8_t slot,
      IN OUT CommandPacket *packet,
      IN Event::Instance event OPTIONAL
  );

  typedef Status(EFIAPI *GetNextSlot)(
      IN struct SdMmcPassThruProtocol *instance,
      IN OUT uint8_t *slot
  );

  typedef Status(EFIAPI *BuildDevicePath)(
      IN struct SdMmcPassThruProtocol *instance,
      IN uint8_t slot,
      OUT DevicePath **devicePath
  );

  typedef Status(EFIAPI *GetSlotNumber)(
      IN struct SdMmcPassThruProtocol *instance,
      IN DevicePath *devicePath,
      OUT uint8_t *slot
  );

  typedef Status(EFIAPI *ResetDevice)(
      IN struct SdMmcPassThruProtocol *instance,
      IN uint8_t slot
  );

  uint64_t ioAlign;
  PassThrough passThrough;
  GetNextSlot getNextSlot;
  BuildDevicePath buildDevicePath;
  GetSlotNumber getSlotNumber;
  ResetDevice resetDevice;
} SdMmcPassThruProtocol;

typedef struct RamDiskProtocol {
  typedef Status(EFIAPI *RegiserRamdisk)(
      IN uintptr_t ramDiskBase,
      IN uint64_t ramDiskSize,
      IN Guid *ramDiskType,
      IN DevicePath *parentDevicePath OPTIONAL,
      OUT DevicePath **fevicePath
  );

  typedef Status(EFIAPI *UnregisterRamdisk)(IN DevicePath *fevicePath);

  RegiserRamdisk registerRamdisk;
  UnregisterRamdisk unregisterRamdisk;
} RamDiskProtocol;

typedef struct {
  enum class PartitionType : uint32_t {
    Other,
    Mbr,
    Gpt
  };

  uint32_t revision;
  PartitionType type;
  uint8_t system;
  uint8_t reserved[7];
  union { // 根据type决定读取的类型
    MasterBootRecord::PartitionRecord mbr;
    GptPartitionEntry gpt;
  } Info;
} __attribute__((packed)) PartitionInfoProtocol;

typedef struct NvdimmLabelProtocol {
  typedef Status(EFIAPI *GetInformation)(
      IN struct NvdimmLabelProtocol *instance,
      OUT uint32_t *SizeOfLabelStorageArea,
      OUT uint32_t *MaxTransferLength
  );

  typedef Status(EFIAPI *Read)(
      IN struct NvdimmLabelProtocol *instance,
      IN uint32_t offset,
      IN uint32_t size,
      OUT uint8_t *buffer
  );

  typedef Status(EFIAPI *Write)(
      IN struct NvdimmLabelProtocol *instance,
      IN uint32_t offset,
      IN uint32_t size,
      IN uint8_t *data
  );

  GetInformation getInformation;
  Read read;
  Write write;
} NvdimmLabelProtocol;

typedef struct UfsDeviceConfigProtocol {
  typedef Status(EFIAPI *RwDescriptor)(
      IN struct UfsDeviceConfigProtocol *instance,
      IN bool isRead,
      IN uint8_t descriptorId,
      IN uint8_t index,
      IN uint8_t selector,
      IN OUT uint8_t descriptor,
      IN OUT uint32_t *descriptorSize
  );

  typedef Status(EFIAPI *RwFlag)(
      IN struct UfsDeviceConfigProtocol *instance,
      IN bool isRead,
      IN uint8_t flagId,
      IN OUT uint8_t *flag
  );

  typedef Status(EFIAPI *RwAttribute)(
      IN struct UfsDeviceConfigProtocol *instance,
      IN bool isRead,
      IN uint8_t attributeId,
      IN uint8_t index,
      IN uint8_t selector,
      IN OUT uint8_t *attribute,
      IN OUT uint32_t *attributeSize
  );

  RwDescriptor rwUfsDescriptor;
  RwFlag rwUfsFlag;
  RwAttribute rwUfsAttribute;
} UfsDeviceConfigProtocol;

namespace FileSystem {

SimpleFilesystemProtocol *getRootfs();

PoolObject<SimpleFilesystemProtocol *> getFilesystemList(uint64_t &count);

PoolObject<const char16_t> normalizePath(const char16_t *path);

} // namespace FileSystem

} // namespace efi